import { createContext, useContext, useEffect, useState } from "react";

// 上下文
export const appContext = createContext(null);

export const store = {
    state: {
        user: {
            name: 'tom',
            age: 99
        },
        group: {
            name: '航海网'
        }
    },
    setState (newState) {
        store.state = newState;
        store.listeners.map(fn => fn(store.state));
    },
    listeners: [],
    subscribe (fn) {
        store.listeners.push(fn);
        return () => {
            const index = store.listeners.indexOf(fn);
            store.listeners.splice(index, 1); // 取消订阅
        }
    },
}

// reduce 用于规范 state 创建流程的函数
const reducer = (state, {type, payload = {}}) => {
    if (type === 'updateUser') {
        return {
            ...state,
            user: {
                ...state.user,
                ...payload
            }
        }
    } else {
        return state;
    }
}

// 判断是否有变化的数据
function changed (oldState, newState) {
    let changed = false;
    for (const key in oldState) {
        if (oldState[key] !== newState[key]) {
            changed = true;
        } 
    }
    return changed;
}

// 高阶组件
export const connect = (selector, dispatchSelector) => (Component) => {
    const Wrapper = (props) => {
        // dispatch 用于规范 setState 的流程
        const dispatch = (action) => {
            setState(reducer(state, action));
            // update({}); // 强制刷新 只会一个组件的更新,有 bug, 解决方案,使用发布订阅
        }
        const { state, setState } = useContext(appContext);
        const [, update] = useState({}); // 只会一个组件的更新,有 bug, 解决方案,使用发布订阅
        
        const data = selector ? selector(state) : {state};
        const dispatchs =  dispatchSelector ? dispatchSelector(dispatch) : {dispatch};

        useEffect(() => {
            // 订阅, 解决只刷新一个组件的问题
            const unsubscrib = store.subscribe(() => {
                const newData = selector ? selector(store.state) : {state: store.state};
                // 判断数据是否更新,减少不必要的更新
                if (changed(data, newData)) {
                    console.log('update');
                    update({});
                }
            });
            return unsubscrib; // 解决可能多次订阅
        }, [selector])

        return <Component {...props} {...data} {...dispatchs}/>
    }

    return Wrapper;
}
